//
// Description: 右值引用、移动构造函数、std::move()
// Created by Loading on 2021/3/18.
//

#include <bits/stdc++.h>

using namespace std;

class demo {
public:
    //构造函数
    demo() : num(new int(0)) {
        cout << "construct!" << endl;
    }

    //拷贝构造函数
    demo(const demo &d) : num(new int(*d.num)) {
        cout << "copy construct!" << endl;
    }

    //移动构造函数
    demo(demo &&d) : num(d.num) {
        d.num = nullptr;
        cout << "move construct!" << endl;
    }

    //析构函数
    ~demo() {
        cout << "destruct!" << endl;
    }

public:
    int *num;
};

demo get_demo() {
    return demo();//调用移动构造函数
}

int main() {
    //右值引用
    int i = 0;
    //和声明左值引用一样，右值引用也必须立即进行初始化操作，且只能使用右值进行初始化
    //int &&j = i; //错误，右值引用只能用右值进行初始化
    int &&j = 0;
    cout << "j:" << j << endl;
    //修改右值引用
    j = 1;
    cout << "j:" << j << endl;


    //移动构造函数
    //当类中同时包含拷贝构造函数和移动构造函数时，如果使用临时对象初始化当前类的对象，编译器会优先调用移动构造函数来完成此操作。
    //只有当类中没有合适的移动构造函数时，编译器才会退而求其次，调用拷贝构造函数。
    demo a = get_demo();/* 调用移动构造函数，需要添加 -fno-elide-constructors 编译，因为编译器会优化 */


    demo b;
    cout << "demo c:" << endl;
    demo c = b;//调用拷贝构造函数
    cout << "b.num:" << *b.num << endl;

    cout << "demo d:" << endl;
    //std::move()  将某个左值强制转化为右值
    demo d = std::move(b);
    //调用移动构造函数后，b.num = nullptr
    //cout << "b.num:" << *b.num << endl; //错误

    return 0;
}